package com.jiukuaidao.library.util;

import android.text.TextUtils;

import com.jiukuaidao.library.config.db.IDBConfig;
import com.jiukuaidao.library.config.db.RealmEntity;

import java.lang.reflect.Method;
import java.util.Date;

import io.realm.Realm;
import io.realm.RealmModel;
import io.realm.RealmObject;
import io.realm.RealmResults;


/**
 * @author : BinarySatan
 *         db bean 必须写 set方法,字段类型不可以加 final、transient、volatile
 *         <p/>
 */
public class DBUtils {


    private static final String mUpdatePrefix = "set";

    public DBUtils() {
    }

    public static synchronized void setDefaultConfig(IDBConfig config) {
//        Realm.deleteRealm(config.createDBConfig());
        Realm.setDefaultConfiguration(config.createDBConfig());
    }


    public static synchronized Realm getDefaultRealm() {
        return Realm.getDefaultInstance();
    }


    public static synchronized void add(final RealmModel bean) {
        getDefaultRealm().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.copyToRealm(bean);
                realm.close();
            }
        });
    }

    /**
     * 根据 key, 来增加或者 更新bean
     */
    public static synchronized void addOrUpdate(final RealmModel bean) {

        getDefaultRealm().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.copyToRealmOrUpdate(bean);
                realm.close();
            }
        });
    }

    /**
     * 把json 转换成 数据库 bean
     */
    public static synchronized void addFromJson(final Class<? extends RealmModel> clazz, final String json) {

        getDefaultRealm().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.createObjectFromJson(clazz, json);
                realm.close();
            }
        });

    }

    /**
     * 删除符合条件所有数据
     *
     * @param clazz
     */
    public static synchronized void deleteAll(Class<? extends RealmModel> clazz) {
        deleteAll(clazz, null, null);
    }

    /**
     * 删除符合条件的所有数据
     */
    public static synchronized void deleteAll(Class<? extends RealmModel> clazz, String fieldName, Object fieldValue) {

        final RealmResults<? extends RealmModel> results;
        final RealmEntity realmEntity;
        if (TextUtils.isEmpty(fieldName) || fieldValue == null) {
            realmEntity = findAll(clazz);
        } else {
            realmEntity = findAll(clazz, fieldName, fieldValue);
        }

        results = realmEntity.getRealmResults();

        getDefaultRealm().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                results.deleteAllFromRealm();
                realm.close();
            }
        });
    }

    /**
     * 根据字段 更新.
     */
    public static synchronized void updateFirst(Class<? extends RealmModel> clazz, String fieldName, Object newFieldValue) {
        updateFirst(clazz, fieldName, null, newFieldValue);
    }

    /**
     * 根据字段的值 更新
     */
    public static synchronized void updateFirst(Class<? extends RealmModel> clazz, String fieldName, Object oldFieldValue, final Object newFieldValue) {
        final RealmEntity realmEntity = oldFieldValue == null ? findFirst(clazz) : findFirst(clazz, fieldName, oldFieldValue);
        final RealmModel result = realmEntity.getRealmModel();
        final Method method = getRelfectionMethod(clazz, fieldName, newFieldValue);

        if (method != null && result != null) {
            getDefaultRealm().executeTransaction(new Realm.Transaction() {
                @Override
                public void execute(Realm realm) {
                    try {
                        method.invoke(result, newFieldValue);
                        realm.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }

    }


    /**
     * 根据字段 修改
     */
    public static synchronized void updateAll(Class<? extends RealmObject> clazz, String fieldName, Object newFieldValue) {
        updateAll(clazz, fieldName, null, newFieldValue);
    }

    /**
     * 根据 字段的值 修改
     */
    public static synchronized void updateAll(final Class<? extends RealmModel> clazz, final String fieldName, Object oldFieldValue, final Object newFieldValue) {
        final RealmEntity realmEntity = oldFieldValue == null ? findAll(clazz) : findAll(clazz, fieldName, oldFieldValue);

        Realm realm = getDefaultRealm();
        realm.beginTransaction();
        RealmResults<RealmModel> results = (RealmResults<RealmModel>) realmEntity.getRealmResults();
        for (RealmModel ro : results) {
            final Method method = getRelfectionMethod(clazz, fieldName, newFieldValue);
            try {
                if (method != null && ro != null) {
                    method.invoke(ro, newFieldValue);
                }
            } catch (Exception e) {
                getDefaultRealm().cancelTransaction();
                e.printStackTrace();
            }
        }
        realm.commitTransaction();
        realm.close();
    }


    public static RealmEntity findFirst(Class<? extends RealmModel> clazz) {
        Realm realm = getDefaultRealm();
        RealmModel realmModel = realm.where(clazz).findFirst();
        return RealmEntity
                .getInstance()
                .setRealm(realm)
                .setRealmModel(realmModel);
    }

    /**
     * 根据字段名 和它的值, 寻找第一个匹配的.
     */
    public static RealmEntity findFirst(Class clazz, String fieldName, Object fieldValue) {

        Realm realm = getDefaultRealm();
        RealmModel realmModel;
        if (fieldValue instanceof String) {
            realmModel = realm.where(clazz).equalTo(fieldName, (String) fieldValue).findFirst();
        } else if (fieldValue instanceof Integer) {
            realmModel = realm.where(clazz).equalTo(fieldName, (Integer) fieldValue).findFirst();
        } else if (fieldValue instanceof Byte) {
            realmModel = realm.where(clazz).equalTo(fieldName, (Byte) fieldValue).findFirst();
        } else if (fieldValue instanceof Short) {
            realmModel = realm.where(clazz).equalTo(fieldName, (Short) fieldValue).findFirst();
        } else if (fieldValue instanceof Long) {
            realmModel = realm.where(clazz).equalTo(fieldName, (Long) fieldValue).findFirst();
        } else if (fieldValue instanceof Double) {
            realmModel = realm.where(clazz).equalTo(fieldName, (Double) fieldValue).findFirst();
        } else if (fieldValue instanceof Float) {
            realmModel = realm.where(clazz).equalTo(fieldName, (Float) fieldValue).findFirst();
        } else if (fieldValue instanceof Boolean) {
            realmModel = realm.where(clazz).equalTo(fieldName, (Boolean) fieldValue).findFirst();
        } else if (fieldValue instanceof Date) {
            realmModel = realm.where(clazz).equalTo(fieldName, (Date) fieldValue).findFirst();
        } else {
            throw new IllegalArgumentException("findFirst fieldValue type not support ");
        }

        return RealmEntity
                .getInstance()
                .setRealm(realm)
                .setRealmModel(realmModel);
    }


    public static RealmEntity findAll(Class<? extends RealmModel> clazz) {
        Realm realm = getDefaultRealm();
        RealmResults results = realm.where(clazz).findAll();
        return RealmEntity
                .getInstance()
                .setRealm(realm)
                .setRealmModelResults(results);
    }


    public static RealmEntity findAll(Class<? extends RealmModel> clazz, String fieldName, Object fieldValue) {
        Realm realm = getDefaultRealm();
        RealmResults results;
        if (fieldValue instanceof String) {
            results = realm.where(clazz).equalTo(fieldName, (String) fieldValue).findAll();
        } else if (fieldValue instanceof Integer) {
            results = realm.where(clazz).equalTo(fieldName, (Integer) fieldValue).findAll();
        } else if (fieldValue instanceof Byte) {
            results = realm.where(clazz).equalTo(fieldName, (Byte) fieldValue).findAll();
        } else if (fieldValue instanceof Short) {
            results = realm.where(clazz).equalTo(fieldName, (Short) fieldValue).findAll();
        } else if (fieldValue instanceof Long) {
            results = realm.where(clazz).equalTo(fieldName, (Long) fieldValue).findAll();
        } else if (fieldValue instanceof Double) {
            results = realm.where(clazz).equalTo(fieldName, (Double) fieldValue).findAll();
        } else if (fieldValue instanceof Float) {
            results = realm.where(clazz).equalTo(fieldName, (Float) fieldValue).findAll();
        } else if (fieldValue instanceof Boolean) {
            results = realm.where(clazz).equalTo(fieldName, (Boolean) fieldValue).findAll();
        } else if (fieldValue instanceof Date) {
            results = realm.where(clazz).equalTo(fieldName, (Date) fieldValue).findAll();
        } else {
            throw new IllegalArgumentException("findAll fieldValue type not support ");
        }
        return RealmEntity
                .getInstance()
                .setRealm(realm)
                .setRealmModelResults(results);

    }


    /**
     * 获取反射方法
     */
    private static Method getRelfectionMethod(Class<? extends RealmModel> clazz, String fieldName, Object newFieldValue) {

        try {
            if (newFieldValue instanceof String) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), String.class);
            } else if (newFieldValue instanceof Integer) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), int.class);
            } else if (newFieldValue instanceof Byte) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), byte.class);
            } else if (newFieldValue instanceof Short) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), short.class);
            } else if (newFieldValue instanceof Long) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), long.class);
            } else if (newFieldValue instanceof Double) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), double.class);
            } else if (newFieldValue instanceof Float) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), float.class);
            } else if (newFieldValue instanceof Boolean) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), boolean.class);
            } else if (newFieldValue instanceof Date) {
                return clazz.getMethod(mUpdatePrefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), Date.class);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
